package cHelper

import (
	"math"
	"slices"
)

// Unique 去重
func Unique[T comparable](data []T, equal func(a, b T) bool) []T {
	var result = make([]T, 0)
	for _, item1 := range data {
		var exists bool
		for _, item2 := range result {
			if equal(item1, item2) {
				exists = true
				break
			}
		}
		if !exists {
			result = append(result, item1)
		}
	}

	return result
}

// Chunk 数组分片
func Chunk[T any](data []T, size uint) (result [][]T) {
	if len(data) == 0 || size == 0 {
		return
	}

	dataLen := len(data)
	count := int(math.Ceil(float64(dataLen) / float64(size)))

	for i := 0; i < count; i++ {
		result = append(result, []T{})
	}

	for index, item := range data {
		key := index / int(size)
		result[key] = append(result[key], item)
	}

	return
}

// InArray 数组是否存在该值
func InArray[T comparable](array []T, data T) (result bool) {
	return slices.Contains(array, data)
}

// KeyBy 按字段转map
func KeyBy[T any, P comparable](data []T, key func(item T) (P, bool)) (result map[P]T) {
	result = make(map[P]T)
	for _, item := range data {
		index, available := key(item)
		if available {
			result[index] = item
		}
	}
	return
}

// Pluck 取字段值
func Pluck[T any, P comparable](array []T, key func(item T) P) (result []P) {
	result = []P{}

	for _, item := range array {
		resultItem := key(item)

		exists := false
		for _, v := range result {
			if v == resultItem {
				exists = true
				break
			}
		}

		if !exists {
			result = append(result, resultItem)
		}
	}

	return
}

// GroupBy 按字段分组
func GroupBy[T any, P comparable](data []T, key func(item T) (P, bool)) (result map[P][]T) {
	result = make(map[P][]T)

	for _, item := range data {
		index, available := key(item)
		if available {
			if _, ok := result[index]; !ok {
				result[index] = []T{}
			}
			result[index] = append(result[index], item)
		}
	}

	return
}

// MappingBy 使用指定字段组成map
func MappingBy[T, V any, K comparable](data []T, f func(item T) (K, V)) (result map[K]V) {
	result = make(map[K]V)

	for _, item := range data {
		k, v := f(item)
		result[k] = v
	}

	return
}

func MappingGroupBy[D, V any, K comparable](data []D, f func(item D) (K, V)) (result map[K][]V) {
	result = make(map[K][]V)

	for _, item := range data {
		k, v := f(item)
		if _, ok := result[k]; !ok {
			result[k] = make([]V, 0)
		}
		result[k] = append(result[k], v)
	}

	return
}

// OrderBy 按字段排序
func OrderBy[T any](data []T, compare func(first, second T) (result bool)) {
	length := len(data)
	for i := 0; i < length; i++ {
		for j := i + 1; j < length; j++ {
			if compare(data[i], data[j]) {
				temp := data[j]
				data[j] = data[i]
				data[i] = temp
			}
		}
	}
}

// IsEqualSlice 判断数组是否相等
func IsEqualSlice[T comparable](value1, value2 []T) bool {
	if len(value1) != len(value2) {
		return false
	}

	count := len(value1)
	for i := 0; i < count; i++ {
		if value1[i] != value2[i] {
			return false
		}
	}

	return true
}

func SwitchSlice[A, B any](data []A, f func(item A) (result B)) []B {
	result := []B{}
	if len(data) == 0 {
		return result
	}

	for _, item := range data {
		b := f(item)
		result = append(result, b)
	}

	return result
}

// Merge 数组并集
func Merge[T any](equal func(a, b T) bool, data ...[]T) []T {
	var result = make([]T, 0)

	if len(data) == 0 {
		return result
	}

	result = append(result, data[0]...)

	if len(data) == 1 {
		return result
	}

	for i, item := range data {
		if i == 0 {
			continue
		}
		for _, val2 := range item {
			var exists bool
			for _, val1 := range result {
				if equal(val1, val2) {
					exists = true
					break
				}
			}
			if !exists {
				result = append(result, val2)
			}
		}
	}

	return result
}

// Intersect 数组交集
func Intersect[T any](equal func(a, b T) bool, data ...[]T) []T {
	var result = make([]T, 0)

	if len(data) == 0 {
		return result
	}

	result = append(result, data[0]...)

	if len(data) == 1 {
		return result
	}

	for i, item := range data {
		if i == 0 {
			continue
		}

		var intersect = make([]T, 0)
		for _, val2 := range item {
			for _, val1 := range result {
				if equal(val1, val2) {
					intersect = append(intersect, val2)
					break
				}
			}
		}
		result = slices.Clone(intersect)
	}

	return result
}

// IntersectIgnoreNil 数组交集，忽略nil元素
func IntersectIgnoreNil[T any](equal func(a, b T) bool, all ...[]T) []T {
	var data = make([][]T, 0)
	for _, item := range all {
		if item != nil {
			data = append(data, item)
		}
	}

	var result = make([]T, 0)

	if len(data) == 0 {
		return result
	}

	result = append(result, data[0]...)

	if len(data) == 1 {
		return result
	}

	for i, item := range data {
		if i == 0 {
			continue
		}

		var intersect = make([]T, 0)
		for _, val2 := range item {
			for _, val1 := range result {
				if equal(val1, val2) {
					intersect = append(intersect, val2)
					break
				}
			}
		}
		result = slices.Clone(intersect)
	}

	return result
}

// Contains 数组是否存在该值
func Contains[T any](data []T, value T, equal func(item, value T) bool) bool {
	for _, item := range data {
		if equal(item, value) {
			return true
		}
	}

	return false
}

// CountBy 数组元素满足条件数量
func CountBy[T any](data []T, f func(item T) bool) int64 {
	var result int64
	for _, item := range data {
		if f(item) {
			result++
		}
	}

	return result
}
